package cn.sciento.starter.lock;


import cn.sciento.core.exception.CommonException;
import cn.sciento.starter.lock.annotation.Lock;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import cn.sciento.starter.lock.factory.LockServiceFactory;
import cn.sciento.starter.lock.service.LockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(0)
public class LockAspectHandler {
  @Autowired
  private LockInfoProvider lockInfoProvider;
  
  @Autowired
  private LockServiceFactory lockFactory;
  
  @Around("@annotation(lock)")
  public Object around(ProceedingJoinPoint joinPoint, Lock lock) throws Throwable {
    LockInfo lockInfo = this.lockInfoProvider.getLockInfo((JoinPoint)joinPoint, lock);
    LockService lockService = this.lockFactory.getLock(lock.lockType());
    if (lockService.getLockInfo() != null && !lockInfo.equals(lockService.getLockInfo()))
      return joinPoint.proceed(); 
    lockService.setLockInfo(lockInfo);
    boolean lockFlag = false;
    try {
      boolean lockRes = lockService.lock();
      if (lockRes) {
        lockFlag = true;
        return joinPoint.proceed();
      } 
      throw new CommonException("Get lock failed.");
    } finally {
      if (lockFlag) {
        lockService.releaseLock();
        lockService.clearLockInfo();
      } 
    } 
  }
}
